use std::rc::Rc;
use chrono::{DateTime, Local};
use serde::{Deserialize, Serialize};
use serde_repr::{Serialize_repr, Deserialize_repr};
use crate::db::pojo::pojo::{ImGroup, ImSession, ImSessionStatus, ImSessionType, ImUser};
use crate::business::websocket::dto::json_serialize::{date_time_serde, date_time_serde_null};
use crate::db::service::im_group_service::ImGroupService;
use crate::db::service::im_user_service::ImUserService;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SessionPullReq {
    #[serde(rename = "pageSize")]
    pub page_size: usize,                      // 获取个数

    #[serde(rename = "startDate", with = "date_time_serde_null")]
    pub start_date: Option<DateTime<Local>>,

    #[serde(rename = "sessionType")]
    pub session_type: SessionType,

    #[serde(rename = "startServerId")]
    pub start_server_id: Option<String>,

    #[serde(rename = "createDateTime", with = "date_time_serde")]
    pub create_date_time: DateTime<Local>,

    #[serde(rename = "localSeq")]
    pub local_seq: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct SessionItem {
    #[serde(rename = "groupId")]
    pub group_id: Option<String>,

    #[serde(rename = "userId")]
    pub user_id: Option<String>,

    #[serde(rename = "serverId")]
    pub server_id: String,

    #[serde(rename = "isWaking")]
    pub is_waking: bool,

    #[serde(rename = "isTop")]
    pub is_top: bool,

    #[serde(rename = "isDisturb")]
    pub is_disturb: bool,

    #[serde(rename = "isWaking2")]
    pub is_waking2: bool,

    #[serde(rename = "isTop2")]
    pub is_top2: bool,

    #[serde(rename = "isDisturb2")]
    pub is_disturb2: bool,

    pub r#type: SessionType,
    pub name: String,
    pub status: SessionStatus,

    #[serde(rename = "updateTime", with = "date_time_serde")]
    pub update_time: DateTime<Local>
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum SessionType {
    Chat = 1,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum SessionStatus {
    Enable = 1,
    Disable = 2,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct SessionItemList {
    #[serde(rename = "sessionItemList")]
    pub session_item_list: Vec<SessionItem>,
}

impl ImSession {
    pub(crate) fn wrap(value: SessionItem, user_id: String) -> ImSession {
        let group_code: Option<String> = value.group_id.clone();
        let data = match group_code.clone() {
            Some(group_code) => {
                let group_service = ImGroupService;
                let group = group_service.query_group(&group_code).unwrap();
                TmpSessionData {name: group.name.clone().unwrap(), to_user: None, to_group: Some(Rc::new(group))}
            }
            None => {
                let user_service = ImUserService;
                let user = user_service.query_by_user_id(&value.user_id.clone().unwrap()).unwrap();
                TmpSessionData {name: user.user_name.clone(), to_user: Some(Rc::new(user)), to_group: None }
            }
        };
        ImSession {
            id: None,
            current_user_id: user_id.clone(),
            name: data.name,
            from_user_id: user_id,
            to_user_id: value.user_id,
            server_id: Some(value.server_id),
            session_type: value.r#type.into(),
            group_code: value.group_id,
            hot_message_total: 0,
            lately_message: "".to_string(),
            is_waking: value.is_waking,
            is_top: value.is_top,
            is_disturb: value.is_disturb,
            is_waking2: value.is_waking,
            is_top2: value.is_disturb,
            is_disturb2: value.is_disturb2,
            ext1: None,
            ext2: None,
            status: value.status.into(),
            create_time: Local::now(),
            update_time: Local::now(),
            to_user: data.to_user,
            group: data.to_group,
        }
    }
}

impl Into<ImSessionStatus> for SessionStatus {
    fn into(self) -> ImSessionStatus {
        match self {
            SessionStatus::Enable => { ImSessionStatus::Enable}
            SessionStatus::Disable => { ImSessionStatus::Disable }
        }
    }
}

impl Into<ImSessionType> for SessionType {
    fn into(self) -> ImSessionType {
        match self { 
            SessionType::Chat => { ImSessionType::Chat } }
    }
}

struct TmpSessionData {
    pub name: String,
    pub to_user: Option<Rc<ImUser>>,
    pub to_group: Option<Rc<ImGroup>>,
}